﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ChartDirector;
using System.Text.RegularExpressions;
using System.Collections;

enum eSubjectMode { KOSPI = 0, FUTURE, OPTION };
enum eTarget { ALL = 0, PERSON, FOREIGN, ORGAN };

namespace GoodTrader.GTChart
{
    public partial class frmSubjectChart : Form
    {
        public frmSubjectChart()
        {
            InitializeComponent();
        }

        private eSubjectMode mMode = eSubjectMode.KOSPI;
        private eTarget mTarget = eTarget.PERSON;

        private double[] kpPerson = null;
        private double[] kpForeign = null;
        private double[] kpOrgan = null;
        private double[] kpTrust = null;
        private double[] kpPension = null;
        private double[] kpNation = null;

        private double[] ftPerson = null;
        private double[] ftForeign = null;
        private double[] ftOrgan = null;

        private double[] opCallPerson = null;
        private double[] opCallOrgan = null;
        private double[] opCallForeign = null;
        private double[] opPutPerson = null;
        private double[] opPutOrgan = null;
        private double[] opPutForeign = null;

        // 이동평균을 위한 여분의 데이터를 설정한다. 이 데이터는 이동평균을 위해서만 사용되고 차트에는 나타나지 않는다.
        private int mExtraPoints = 20;
        private int mIndex = 10;
        private GTDownload.CpDataSet mCpDataSetObj = null;
        public GTDownload.CpDataSet CpDataSetObj
        {
            get { return mCpDataSetObj; }
            set { mCpDataSetObj = value; }
        }

        // Will set to true at the end of initialization - prevents events from firing before the
        // controls are properly initialized.
        private bool hasFinishedInitialization = false;

        private void frmSubjectChart_Load(object sender, EventArgs e)
        {
            hasFinishedInitialization = true;
            //drawChart(winChartViewer1);
            InitTimer();
            // 차트 확대 축소와 관련된 사항을 초기화 한다.
            initChartViewer(chartCtrl);
            // Some Visual Studio versions do not expose the MouseWheel event in the Property window, so we
            // need to set up the event handler with our own code.
            chartCtrl.MouseWheel += new MouseEventHandler(chartCtrl_MouseWheel);

            // Trigger the ViewPortChanged event to draw the chart
            chartCtrl.updateViewPort(true, true);
            InitSubjectList();
            // 첫번째 항목을 선택하게 해준다.
            comboOpCode.SelectedIndex = 0;
            // 콤보와 데이터 선택을 일치 시킨다.
            mIndex = comboOpCode.SelectedIndex;
            InitTarget();
            comboTarget.SelectedIndex = 0;
            mTarget = eTarget.ALL;
        }

        private void InitTarget()
        {
            comboTarget.Items.Add("전체");
            comboTarget.Items.Add("개인");
            comboTarget.Items.Add("외국인");
            comboTarget.Items.Add("기관");
        }
        /**
         * @brief 이 함수는 옵션 코드를 가져와서 콤보박스에 넣어준다.
         */ 
        private void InitSubjectList()
        {
            comboOpCode.Items.Add("코스피");
            comboOpCode.Items.Add("선물");
            comboOpCode.Items.Add("옵션");
        }

        private void chartCtrl_MouseEnter(object sender, EventArgs e)
        {
            // Save the original active control and set the WinChartViewer to be the active control, so that
            // the WinChartViewer can receive the mouse wheel event.
            activeControl = chartCtrl.FindForm().ActiveControl;
            chartCtrl.FindForm().ActiveControl = chartCtrl;
        }

        private void chartCtrl_MouseLeave(object sender, EventArgs e)
        {
            // Restore the original active control.
            chartCtrl.FindForm().ActiveControl = activeControl;
        }

        private void chartCtrl_MouseMovePlotArea(object sender, MouseEventArgs e)
        {
            WinChartViewer viewer = (WinChartViewer)sender;
            //trackFinance((MultiChart)viewer.Chart, viewer.PlotAreaMouseX, viewer.PlotAreaMouseY);
            trackLineLegend((XYChart)viewer.Chart, viewer.PlotAreaMouseX);
            //trackLineLabel((XYChart)viewer.Chart, viewer.PlotAreaMouseX);
            viewer.updateDisplay();
        }

        //
        // Draw finance chart track line with legend
        //
        private void trackFinance(MultiChart m, int mouseX, int mouseY)
        {
            // Clear the current dynamic layer and get the DrawArea object to draw on it.
            DrawArea d = m.initDynamicLayer();

            // It is possible for a FinanceChart to be empty, so we need to check for it.
            if (m.getChartCount() == 0)
            {
                return;
            }

            
            // 여분의 점이 있기때문에 현재 x좌표를 참조할 때는 원래 데이터에서 여분의 데이터를 더한 값이 현재 값이 된다.
            // 예를 들면 데이터가 450개이고 여분데이터를 20으로 설정했을 때, 현재 인덱스가 45 이면 원래값은 45 + 20을 해야 원래값을 가져올 수 있다.
            // Get the data x-value that is nearest to the mouse
            int xValue = (int)(((XYChart)m.getChart(0)).getNearestXValue(mouseX));
            

            // Iterate the XY charts (main price chart and indicator charts) in the FinanceChart
            XYChart c = null;
            for (int i = 0; i < m.getChartCount(); ++i)
            {
                c = (XYChart)m.getChart(i);

                // Variables to hold the legend entries
                string ohlcLegend = "";
                ArrayList legendEntries = new ArrayList();

                // Iterate through all layers to find the highest data point
                for (int j = 0; j < c.getLayerCount(); ++j)
                {
                    Layer layer = c.getLayerByZ(j);
                    int xIndex = layer.getXIndexOf(xValue);
                    int dataSetCount = layer.getDataSetCount();

                    // In a FinanceChart, only layers showing OHLC data can have 4 data sets
                    if (dataSetCount == 4)
                    {
                        double highValue = layer.getDataSet(0).getValue(xIndex);
                        double lowValue = layer.getDataSet(1).getValue(xIndex);
                        double openValue = layer.getDataSet(2).getValue(xIndex);
                        double closeValue = layer.getDataSet(3).getValue(xIndex);

                        if (closeValue != Chart.NoValue)
                        {

                            // Build the OHLC legend
                            ohlcLegend = "xIndex :: " + xIndex.ToString() + "Open: " + c.formatValue(openValue, "{value|P4}") + ", High: " +
                                c.formatValue(highValue, "{value|P4}") + ", Low: " + c.formatValue(lowValue,
                                "{value|P4}") + ", Close: " + c.formatValue(closeValue, "{value|P4}");

                            // We also draw an upward or downward triangle for up and down days and the %
                            // change
                            double lastCloseValue = layer.getDataSet(3).getValue(xIndex - 1);
                            if (lastCloseValue != Chart.NoValue)
                            {
                                double change = closeValue - lastCloseValue;
                                double percent = change * 100 / closeValue;
                                string symbol = ((change >= 0) ?
                                    "<*font,color=008800*><*img=@triangle,width=8,color=008800*>" :
                                    "<*font,color=CC0000*><*img=@invertedtriangle,width=8,color=CC0000*>");

                                ohlcLegend = ohlcLegend + "  " + symbol + " " + c.formatValue(change,
                                    "{value|P4}") + " (" + c.formatValue(percent, "{value|2}") + "%)<*/font*>"
                                    ;
                            }

                            // Use a <*block*> to make sure the line does not wrap within the legend entry
                            ohlcLegend = "<*block*>" + ohlcLegend + "      <*/*>";
                        }
                    }
                    else
                    {
                        // Iterate through all the data sets in the layer
                        for (int k = 0; k < layer.getDataSetCount(); ++k)
                        {
                            ChartDirector.DataSet dataSet = layer.getDataSetByZ(k);

                            string name = dataSet.getDataName();
                            double value = dataSet.getValue(xIndex);
                            if ((!string.IsNullOrEmpty(name)) && (value != Chart.NoValue))
                            {

                                // In a FinanceChart, the data set name consists of the indicator name and its
                                // latest value. It is like "Vol: 123M" or "RSI (14): 55.34". As we are
                                // generating the values dynamically, we need to extract the indictor name
                                // out, and also the volume unit (if any).

                                // The unit character, if any, is the last character and must not be a digit.
                                string unitChar = name.Substring(name.Length - 1);
                                if (unitChar.CompareTo("0") >= 0 && unitChar.CompareTo("9") <= 0)
                                {
                                    unitChar = "";
                                }

                                // The indicator name is the part of the name up to the colon character.
                                int delimiterPosition = name.IndexOf(":");
                                if (delimiterPosition != -1)
                                {
                                    name = name.Substring(0, delimiterPosition);
                                }

                                // In a FinanceChart, if there are two data sets, it must be representing a
                                // range.
                                if (dataSetCount == 2)
                                {
                                    // We show both values in the range in a single legend entry
                                    value = layer.getDataSet(0).getValue(xIndex);
                                    double value2 = layer.getDataSet(1).getValue(xIndex);
                                    name = name + ": " + c.formatValue(Math.Min(value, value2), "{value|P3}")
                                         + " - " + c.formatValue(Math.Max(value, value2), "{value|P3}");
                                }
                                else
                                {
                                    // In a FinanceChart, only the layer for volume bars has 3 data sets for
                                    // up/down/flat days
                                    if (dataSetCount == 3)
                                    {
                                        // The actual volume is the sum of the 3 data sets.
                                        value = layer.getDataSet(0).getValue(xIndex) + layer.getDataSet(1
                                            ).getValue(xIndex) + layer.getDataSet(2).getValue(xIndex);
                                    }

                                    // Create the legend entry
                                    name = name + " : " + c.formatValue(value, "{value|P3}") + unitChar;
                                }

                                // Build the legend entry, consist of a colored square box and the name (with
                                // the data value in it).
                                legendEntries.Add("<*block*><*img=@square,width=8,edgeColor=000000,color=" +
                                    dataSet.getDataColor().ToString("x") + "*> " + name + "<*/*>");
                            }
                        }
                    }
                }

                // Get the plot area position relative to the entire FinanceChart
                PlotArea plotArea = c.getPlotArea();
                int offsetX = c.getAbsOffsetX();
                int offsetY = c.getAbsOffsetY();
                int plotAreaLeftX = plotArea.getLeftX() + offsetX;
                int plotAreaTopY = plotArea.getTopY() + offsetY;

                double yValue = c.getYValue(mouseY, c.yAxis());

                // The legend is formed by concatenating the legend entries.
                legendEntries.Reverse();
                string legendText = String.Join("      ", (string[])legendEntries.ToArray(typeof(string)));

                // Add the date and the ohlcLegend (if any) at the beginning of the legend
                legendText = "<*block,valign=top,maxWidth=" + (plotArea.getWidth() - 5) +
                    "*><*font=Arial Bold*>[" + c.xAxis().getFormattedLabel(xValue, "mmm dd, yyyy") +
                    "]<*/font*>      " + ohlcLegend + legendText;

                // Draw a vertical track line at the x-position
                //d.vline(plotAreaTopY, plotAreaTopY + plotArea.getHeight(), c.getXCoor(xValue) + c.getAbsOffsetX(), d.dashLineColor(0x000000, 0x0101));
                int plotHeight = plotArea.getHeight();
                int plotWidth = plotArea.getWidth();
                int width = plotWidth + 0;
                //d.vline(plotAreaTopY, plotAreaTopY + plotHeight, c.getXCoor(xValue) + c.getAbsOffsetX(), d.dashLineColor(0x000000, 0x0101));
                //d.hline(plotArea.getLeftX(), plotArea.getRightX(), c.getYCoor(yValue) + c.getAbsOffsetY(), d.dashLineColor(0x000000, 0x0101));
                // Draw a vertical track line at the x-position
                d.vline(plotAreaTopY, plotAreaTopY + plotArea.getHeight(), c.getXCoor(xValue) +
                    c.getAbsOffsetX(), d.dashLineColor(0x000000, 0x0101));

                // Draw a vertical track line at the x-position
                d.hline(plotArea.getLeftX(), plotArea.getRightX(), c.getYCoor(yValue) +
                    c.getAbsOffsetY(), d.dashLineColor(0x000000, 0x0101));

                // Display the legend on the top of the plot area
                TTFText t = d.text(legendText, "Arial", 8);
                t.draw(plotAreaLeftX + 5, plotAreaTopY + 13, 0x000000, Chart.TopLeft);


                // Draw y-axis label
                string label = "<*block,bgColor=FFFFDD,margin=3,edgeColor=000000*>" + c.formatValue(c.getYValue(
                    mouseY, c.yAxis()), "{value|P4}") + "<*/*>";
                TTFText tAxis = d.text(label, "Arial Bold", 8);
                tAxis.draw(plotArea.getLeftX() - 5, mouseY, 0x000000, Chart.Right);
                Layer topLayer = c.getLayerByZ(0);
                int topIndex = topLayer.getXIndexOf(xValue);
                int startIndex = (int)Math.Floor(chartCtrl.getValueAtViewPort("x", chartCtrl.ViewPortLeft));
                int curIndex = topIndex + startIndex + mExtraPoints;
                
                // label = "<*block,bgColor=FFFFDD,margin=3,edgeColor=000000*>" + c.formatValue( mouseX, "MouseX = {value|P4}") + c.formatValue( mouseY, "MouseY = {value|P4}") + "<*/*>";
                // TTFText txtMouse = d.text(label, "Arial Bold", 8);
                // txtMouse.draw(plotArea.getLeftX() + 100, plotArea.getTopY() - 30, 0x000000, Chart.Right);
            }
        }

        //trackLineLegend((XYChart)viewer.Chart, viewer.PlotAreaMouseX);
        //trackLineLegend(c, viewer.IsMouseOnPlotArea ? viewer.PlotAreaMouseX :
        //        c.getPlotArea().getRightX());
        // 이 함수는 선형 그래프의 라인을 추적하여 그 값을 범례에 보여준다.
        private void trackLineLegend(XYChart c, int mouseX)
        {
            // Clear the current dynamic layer and get the DrawArea object to draw on it.
            DrawArea d = c.initDynamicLayer();

            // The plot area object
            PlotArea plotArea = c.getPlotArea();

            // Get the data x-value that is nearest to the mouse, and find its pixel coordinate.
            double xValue = c.getNearestXValue(mouseX);
            int xCoor = c.getXCoor(xValue);

            // Draw a vertical track line at the x-position
            d.vline(plotArea.getTopY(), plotArea.getBottomY(), xCoor, d.dashLineColor(0x000000, 0x0101));

            // Container to hold the legend entries
            ArrayList legendEntries = new ArrayList();


            // Draw a label on the x-axis to show the track line position.
            string xlabel = "<*font,bgColor=000000*> " + c.xAxis().getFormattedLabel(xValue, "mmm dd, yyyy") +
                " <*/font*>";
            TTFText t = d.text(xlabel, "Arial Bold", 8);


            // Iterate through all layers to build the legend array
            for (int i = 0; i < c.getLayerCount(); ++i)
            {
                Layer layer = c.getLayerByZ(i);

                // The data array index of the x-value
                int xIndex = layer.getXIndexOf(xValue);

                // Iterate through all the data sets in the layer
                for (int j = 0; j < layer.getDataSetCount(); ++j)
                {
                    ChartDirector.DataSet dataSet = layer.getDataSetByZ(j);

                    // We are only interested in visible data sets with names
                    string dataName = dataSet.getDataName();
                    int color = dataSet.getDataColor();
                    if ((!string.IsNullOrEmpty(dataName)) && (color != Chart.Transparent))
                    {
                        // Build the legend entry, consist of the legend icon, name and data value.
                        double dataValue = dataSet.getValue(xIndex);
                        legendEntries.Add("<*block*>" + dataSet.getLegendIcon() + " " + dataName + ": " + ((
                            dataValue == Chart.NoValue) ? "N/A" : c.formatValue(dataValue, "{value|P4}")) +
                            "<*/*>");

                        // Draw a track dot for data points within the plot area
                        int yCoor = c.getYCoor(dataSet.getPosition(xIndex), dataSet.getUseYAxis());
                        if ((yCoor >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY()))
                        {
                            d.circle(xCoor, yCoor, 4, 4, color, color);
                        }

                        string label = "<*font,bgColor=" + color.ToString("x") + "*> " + c.formatValue(
                            dataSet.getValue(xIndex), "{value|P4}") + " <*/font*>";
                        t = d.text(label, "Arial Bold", 8);

                        // Draw the label on the right side of the dot if the mouse is on the left side the
                        // chart, and vice versa. This ensures the label will not go outside the chart image.
                        if (xCoor <= (plotArea.getLeftX() + plotArea.getRightX()) / 2)
                        {
                            t.draw(xCoor + 5, yCoor, 0xffffff, Chart.Left);
                        }
                        else
                        {
                            t.draw(xCoor - 5, yCoor, 0xffffff, Chart.Right);
                        }
                    }
                }
            }

            // Create the legend by joining the legend entries
            legendEntries.Reverse();
            string legendText = "<*block,maxWidth=" + plotArea.getWidth() + "*><*block*><*font=Arial Bold*>["
                 + c.xAxis().getFormattedLabel(xValue, "hh:nn:ss.ff") + "]<*/*>        " + String.Join(
                "        ", (string[])legendEntries.ToArray(typeof(string))) + "<*/*>";

            // Display the legend on the top of the plot area
            TTFText t2 = d.text(legendText, "Arial", 8);
            t2.draw(plotArea.getLeftX() + 5, plotArea.getTopY() - 3, 0x000000, Chart.BottomLeft);
        }


        //
        // Draw track line with data labels
        //
        private void trackLineLabel(XYChart c, int mouseX)
        {
            // Clear the current dynamic layer and get the DrawArea object to draw on it.
            DrawArea d = c.initDynamicLayer();

            // The plot area object
            PlotArea plotArea = c.getPlotArea();

            // Get the data x-value that is nearest to the mouse, and find its pixel coordinate.
            double xValue = c.getNearestXValue(mouseX);
            int xCoor = c.getXCoor(xValue);

            // Draw a vertical track line at the x-position
            //d.vline(plotArea.getTopY(), plotArea.getBottomY(), xCoor, d.dashLineColor(0x000000, 0x0101));

            // Draw a label on the x-axis to show the track line position.
            string xlabel = "<*font,bgColor=000000*> " + c.xAxis().getFormattedLabel(xValue, "mmm dd, yyyy") +
                " <*/font*>";
            TTFText t = d.text(xlabel, "Arial Bold", 8);

            // Restrict the x-pixel position of the label to make sure it stays inside the chart image.
            int xLabelPos = Math.Max(0, Math.Min(xCoor - t.getWidth() / 2, c.getWidth() - t.getWidth()));
            t.draw(xLabelPos, plotArea.getBottomY() + 6, 0xffffff);

            // Iterate through all layers to draw the data labels
            for (int i = 0; i < c.getLayerCount(); ++i)
            {
                Layer layer = c.getLayerByZ(i);

                // The data array index of the x-value
                int xIndex = layer.getXIndexOf(xValue);

                // Iterate through all the data sets in the layer
                for (int j = 0; j < layer.getDataSetCount(); ++j)
                {
                    ChartDirector.DataSet dataSet = layer.getDataSetByZ(j);

                    // Get the color and position of the data label
                    int color = dataSet.getDataColor();
                    int yCoor = c.getYCoor(dataSet.getPosition(xIndex), dataSet.getUseYAxis());

                    // Draw a track dot with a label next to it for visible data points in the plot area
                    if ((yCoor >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY()) && (color !=
                        Chart.Transparent))
                    {

                        d.circle(xCoor, yCoor, 4, 4, color, color);

                        string label = "<*font,bgColor=" + color.ToString("x") + "*> " + c.formatValue(
                            dataSet.getValue(xIndex), "{value|P4}") + " <*/font*>";
                        t = d.text(label, "Arial Bold", 8);

                        // Draw the label on the right side of the dot if the mouse is on the left side the
                        // chart, and vice versa. This ensures the label will not go outside the chart image.
                        if (xCoor <= (plotArea.getLeftX() + plotArea.getRightX()) / 2)
                        {
                            t.draw(xCoor + 5, yCoor, 0xffffff, Chart.Left);
                        }
                        else
                        {
                            t.draw(xCoor - 5, yCoor, 0xffffff, Chart.Right);
                        }
                    }
                }
            }
        }



        private void chartCtrl_ViewPortChanged(object sender, ChartDirector.WinViewPortEventArgs e)
        {
            // In addition to updating the chart, we may also need to update other controls that
            // changes based on the view port.
            updateControls(chartCtrl);

            if (hasFinishedInitialization)
                drawChart(chartCtrl);

            // We need to update the track line too. If the mouse is moving on the chart (eg. if 
            // the user drags the mouse on the chart to scroll it), the track line will be updated
            // in the MouseMovePlotArea event. Otherwise, we need to update the track line here.
            if (mClosing == false && (!chartCtrl.IsInMouseMoveEvent) && chartCtrl.IsMouseOnPlotArea)
            {
                WinChartViewer viewer = (WinChartViewer)sender;
                //trackFinance((MultiChart)viewer.Chart, viewer.PlotAreaMouseX, viewer.PlotAreaMouseY);
                trackLineLegend((XYChart)viewer.Chart, viewer.PlotAreaMouseX);
                //trackLineLabel((XYChart)viewer.Chart, viewer.PlotAreaMouseX);
                chartCtrl.updateDisplay();
            }
        }

        private void chartCtrl_Paint(object sender, PaintEventArgs e)
        {
            XYChart m = (XYChart)chartCtrl.Chart;

            DrawArea d = m.initDynamicLayer();

            // The plot area object
            PlotArea plotArea = m.getPlotArea();

            // Get the data x-value that is nearest to the mouse, and find its pixel coordinate.
            double xValue = 100;
            int xCoor = m.getXCoor(xValue);


            Layer layer = m.getLayerByZ(0);

            // The data array index of the x-value
            int xIndex = layer.getXIndexOf(xValue);

            ChartDirector.DataSet dataSet = layer.getDataSetByZ(0);

            // Get the color and position of the data label
            int color = dataSet.getDataColor();
            int yCoor = m.getYCoor(dataSet.getPosition(xIndex), dataSet.getUseYAxis());

            // Draw a track dot with a label next to it for visible data points in the plot area
            if ((yCoor >= plotArea.getTopY()) && (yCoor <= plotArea.getBottomY()) && (color !=
                Chart.Transparent))
            {
                d.circle(xCoor, yCoor, 4, 4, color, color);
            }
        }

        // Variable to save the original active control
        private Control activeControl = null;

        private void chartCtrl_MouseWheel(object sender, MouseEventArgs e)
        {
            // We zoom in or out by 10% depending on the mouse wheel direction.
            //double r = e.Delta > 0 ? 0.9 : 1 / 0.9;
            // We do not zoom in beyond the zoom in width limit.
            //if ((r = Math.Max(r, chartCtrl.ZoomInWidthLimit / chartCtrl.ViewPortWidth)) == 1)
            //    return;

            // We zoom in or out by 10% depending on the mouse wheel direction.
            double rx = e.Delta > 0 ? 0.9 : 1 / 0.9;
            double ry = rx;

            // We do not zoom in beyond the zoom in width or height limit.
            rx = Math.Max(rx, chartCtrl.ZoomInWidthLimit / chartCtrl.ViewPortWidth);
            ry = Math.Max(ry, chartCtrl.ZoomInWidthLimit / chartCtrl.ViewPortHeight);
            if ((rx == 1) && (ry == 1))
                return;

            XYChart m = (XYChart)chartCtrl.Chart;
            //FinanceChart c = (FinanceChart)chartCtrl.Chart;
            //XYChart m = (XYChart)c.getChart(0);

            double mouseOffset = (chartCtrl.ChartMouseX - m.getPlotArea().getLeftX()) /
                (double)m.getPlotArea().getWidth();
            chartCtrl.ViewPortLeft += mouseOffset * (1 - rx) * chartCtrl.ViewPortWidth;
            chartCtrl.ViewPortWidth *= rx;

            double mouseOffsetY = (chartCtrl.ChartMouseY - m.getPlotArea().getTopY()) /
                (double)m.getPlotArea().getHeight();
            chartCtrl.ViewPortTop += mouseOffsetY * (1 - ry) * chartCtrl.ViewPortHeight;
            chartCtrl.ViewPortHeight *= ry;

            // Trigger a view port changed event to update the chart
            chartCtrl.updateViewPort(true, false);
        }

        private void hChartCtrlScrollBar_ValueChanged(object sender, EventArgs e)
        {
            // When the view port is changed (user drags on the chart to scroll), the scroll bar will get
            // updated. When the scroll bar changes (eg. user drags on the scroll bar), the view port will
            // get updated. This creates an infinite loop. To avoid this, the scroll bar can update the 
            // view port only if the view port is not updating the scroll bar.
            if (hasFinishedInitialization && !chartCtrl.IsInViewPortChangedEvent)
            {
                // Set the view port based on the scroll bar
                chartCtrl.ViewPortLeft = ((double)(hChartScrollBar.Value - hChartScrollBar.Minimum))
                    / (hChartScrollBar.Maximum - hChartScrollBar.Minimum);

                // Trigger a view port changed event to update the chart
                chartCtrl.updateViewPort(true, false);
            }
        }

        //
        // Update controls when the view port changed
        //
        private void updateControls(WinChartViewer viewer)
        {
            // Update the scroll bar to reflect the view port position and width of the view port.
            hChartScrollBar.Enabled = chartCtrl.ViewPortWidth < 1;
            hChartScrollBar.LargeChange = (int)Math.Ceiling(chartCtrl.ViewPortWidth *
                (hChartScrollBar.Maximum - hChartScrollBar.Minimum));
            hChartScrollBar.SmallChange = (int)Math.Ceiling(hChartScrollBar.LargeChange * 0.1);
            hChartScrollBar.Value = (int)Math.Round(chartCtrl.ViewPortLeft *
                (hChartScrollBar.Maximum - hChartScrollBar.Minimum)) + hChartScrollBar.Minimum;
        }
             
        /**
         * @brief 차트 확대 축소에 대한 기본적인 사항을 초기화 한다.
         * @param viewer : 차트 뷰어 컨트롤
         * @remark 차트 뷰어에 속한 전체 범위 설정, 최초 뷰 포트 너비, 좌우측 경계 및 최대 확대 영역 제한을 설정한다.
         */
        private void initChartViewer(WinChartViewer viewer)
        {
            // Set the full x range to be the duration of the data
            // 전체 범위를 나타낸다. 맨앞의 문자열은 범위를 표시하는 고유 문자열이며, 나머지 두 매개변수는 최소값과 최대값을 나타낸다.
            viewer.setFullRange("x", 0, mCpDataSetObj.Svr7221Data.cTime.Length - 1);

            // Initialize the view port to show the latest 20% of the time range
            // 최초 표시 범위
            viewer.ViewPortWidth = 0.2;
            // 최초 표시 시작 점
            viewer.ViewPortLeft = 1 - viewer.ViewPortWidth;

            // 전체 범위에 대한 부분 범위를 나타낸다. 예를 들면 x데이터가 450개일 경우 10/450 이면 0.02%정도 된다.
            viewer.ZoomInWidthLimit = 10.0 / mCpDataSetObj.Svr7221Data.cTime.Length;

            // Initially set the mouse usage to "Pointer" mode (Drag to Scroll mode)
            //pointerPB.Checked = true;
        }

        /// <summary>
        /// Draw the chart according to user selection and display it in the WinChartViewer.
        /// </summary>
        /// <param name="viewer">The WinChartViewer object to display the chart.</param>
        private void drawChart(WinChartViewer viewer)
        {

            // Get the array indexes that corresponds to the visible start and end dates
            int startIndex = (int)Math.Floor(viewer.getValueAtViewPort("x", viewer.ViewPortLeft));
            int endIndex = (int)Math.Ceiling(viewer.getValueAtViewPort("x", viewer.ViewPortLeft + viewer.ViewPortWidth));
            int noOfPoints = endIndex - startIndex + 1;

            // Extract the part of the data array that are visible.
            DateTime[] dataSysTime = (DateTime[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.SysTime, startIndex, noOfPoints);

            if (mMode == eSubjectMode.KOSPI)
            {
                if (mTarget == eTarget.ALL)
                {
                    kpForeign = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.KPForeign, startIndex, noOfPoints);
                    kpOrgan = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.KPOrgan, startIndex, noOfPoints);
                    kpTrust = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.KPTrust, startIndex, noOfPoints);
                    kpPension = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.KPPension, startIndex, noOfPoints);
                    kpNation = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.KPNation, startIndex, noOfPoints);
                    kpPerson = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.KPPerson, startIndex, noOfPoints);
                }
                else if (mTarget == eTarget.PERSON)
                {
                    kpPerson = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.KPPerson, startIndex, noOfPoints);
                }
                else if (mTarget == eTarget.FOREIGN)
                {
                    kpForeign = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.KPForeign, startIndex, noOfPoints);
                }
                else
                {
                    kpOrgan = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.KPOrgan, startIndex, noOfPoints);
                }
            }
            else if (mMode == eSubjectMode.FUTURE)
            {
                if (mTarget == eTarget.ALL)
                {
                    ftForeign = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.FTForeign, startIndex, noOfPoints);
                    ftOrgan = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.FTOrgan, startIndex, noOfPoints);
                    ftPerson = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.FTPerson, startIndex, noOfPoints);
                }
                else if (mTarget == eTarget.PERSON)
                {
                    ftPerson = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.FTPerson, startIndex, noOfPoints);
                }
                else if (mTarget == eTarget.FOREIGN)
                {
                    ftForeign = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.FTForeign, startIndex, noOfPoints);
                }
                else
                {
                    ftOrgan = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.FTOrgan, startIndex, noOfPoints);
                }
            }
            else
            {
                if (mTarget == eTarget.ALL)
                {
                    opCallForeign = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTForeignCall, startIndex, noOfPoints);
                    opCallOrgan = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTOrganCall, startIndex, noOfPoints);
                    opCallPerson = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTPersonCall, startIndex, noOfPoints);
                    opPutForeign = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTForeignPut, startIndex, noOfPoints);
                    opPutOrgan = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTOrganPut, startIndex, noOfPoints);
                    opPutPerson = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTPersonPut, startIndex, noOfPoints);
                }
                else if (mTarget == eTarget.PERSON)
                {
                    opCallPerson = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTPersonCall, startIndex, noOfPoints);
                    opPutPerson = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTPersonPut, startIndex, noOfPoints);
                }
                else if (mTarget == eTarget.FOREIGN)
                {
                    opCallForeign = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTForeignCall, startIndex, noOfPoints);
                    opPutForeign = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTForeignPut, startIndex, noOfPoints);
                }
                else
                {
                    opCallOrgan = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTOrganCall, startIndex, noOfPoints);
                    opPutOrgan = (double[])Chart.arraySlice(mCpDataSetObj.Svr7221Data.OTOrganPut, startIndex, noOfPoints);
                }
            }
            
            // We need extra leading data points in order to compute moving averages.
            //int extraPoints = 20;

            // Create the chart object using the selected size
            //FinanceChart m = new FinanceChart(panelBody.Width);
            XYChart m = new XYChart(panelBody.Width, panelBody.Height, 0xf4f4f4, 0x000000, 1);


            // A copyright message at the bottom left corner the title area
            m.addTitle(Chart.BottomRight, "<*font=arial.ttf,size=8*>Good Trader Engineering");

            //mainChart.setPlotArea(50, 50, mainChart.getWidth(), mainChart.getHeight() - hChartScrollBar.Height);
            m.setPlotArea(50, 80, chartCtrl.Width - 100, chartCtrl.Height - 130, 0xffffff, -1, 0xc0c0c0, 0xc0c0c0, -1);

            // Create a line layer to plot the lines
            LineLayer layer = m.addLineLayer2();

            // The x-coordinates are the timeStamps.
            layer.setXData(dataSysTime);

            if (mMode == eSubjectMode.KOSPI)
            {
                if (mTarget == eTarget.ALL)
                {
                    layer.addDataSet(kpPerson, 0xff0000, "코스피 : 개인");
                    layer.addDataSet(kpForeign, 0x00cc00, "코스피 : 외국인");
                    layer.addDataSet(kpOrgan, 0x0000ff, "코스피 : 기관");
                    layer.addDataSet(kpTrust, 0xff00ff, "코스피 : 투신");
                    layer.addDataSet(kpPension, 0xffcc00, "코스피 : 연금");
                    layer.addDataSet(kpNation, 0x00ffff, "코스피 : 국가");
                }
                else if (mTarget == eTarget.PERSON)
                {
                    layer.addDataSet(kpPerson, 0xff0000, "코스피 : 개인");
                }
                else if (mTarget == eTarget.FOREIGN)
                {
                    layer.addDataSet(kpForeign, 0x00cc00, "코스피 : 외국인");
                }
                else
                {
                    layer.addDataSet(kpOrgan, 0x0000ff, "코스피 : 기관");
                }
            }
            else if (mMode == eSubjectMode.FUTURE)
            {
                if (mTarget == eTarget.ALL)
                {
                    layer.addDataSet(ftPerson, 0xff0000, "선물 : 개인");
                    layer.addDataSet(ftForeign, 0x00cc00, "선물 : 외국인");
                    layer.addDataSet(ftOrgan, 0x0000ff, "선물 : 기관");
                }
                else if (mTarget == eTarget.PERSON)
                {
                    layer.addDataSet(ftPerson, 0xff0000, "선물 : 개인");
                }
                else if (mTarget == eTarget.FOREIGN)
                {
                    layer.addDataSet(ftForeign, 0x00cc00, "선물 : 외국인");
                }
                else
                {
                    layer.addDataSet(ftOrgan, 0x0000ff, "선물 : 기관");
                }
            }
            else
            {
                if (mTarget == eTarget.ALL)
                {
                    layer.addDataSet(opCallPerson, 0xff0000, "옵션콜 : 개인");
                    layer.addDataSet(opCallForeign, 0x00cc00, "옵션콜 : 외국인");
                    layer.addDataSet(opCallOrgan, 0x0000ff, "옵션콜 : 기관");
                    layer.addDataSet(opPutPerson, 0xff00ff, "옵션풋 : 개인");
                    layer.addDataSet(opPutForeign, 0xffcc00, "옵션풋 : 외국인");
                    layer.addDataSet(opPutOrgan, 0x00ccff, "옵션풋 : 기관");
                }
                else if (mTarget == eTarget.PERSON)
                {
                    layer.addDataSet(opCallPerson, 0xff0000, "옵션콜 : 개인");
                    layer.addDataSet(opPutPerson, 0xff00ff, "옵션풋 : 개인");
                }
                else if (mTarget == eTarget.FOREIGN)
                {
                    layer.addDataSet(opCallForeign, 0x00cc00, "옵션콜 : 외국인");
                    layer.addDataSet(opPutForeign, 0xffcc00, "옵션풋 : 외국인");
                }
                else
                {
                    layer.addDataSet(opCallOrgan, 0x0000ff, "옵션콜 : 기관");
                    layer.addDataSet(opPutOrgan, 0x00ccff, "옵션풋 : 기관");
                }
            }

            // Include track line with legend. If the mouse is on the plot area, show the track 
            // line with legend at the mouse position; otherwise, show them for the latest data
            // values (that is, at the rightmost position).
            if (mClosing == false)
                trackLineLegend(m, viewer.IsMouseOnPlotArea ? viewer.PlotAreaMouseX : m.getPlotArea().getRightX());
            //trackLineLabel(m, viewer.IsMouseOnPlotArea ? viewer.PlotAreaMouseX : m.getPlotArea().getRightX());
            // output the chart
            //
            viewer.Chart = m;

            //
            // tooltips for the chart
            //
            //viewer.ImageMap = m.getHTMLImageMap("", "", "title='" + m.getToolTip() + " {value|P}'");

            //trackFinance((MultiChart)viewer.Chart, viewer.IsMouseOnPlotArea ? viewer.PlotAreaMouseX : mainChart.getPlotArea().getRightX(), viewer.PlotAreaMouseY);
        }

        private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
        private void InitTimer()
        {
            timer.Interval = 1000;
            timer.Tick += new EventHandler(OnTimerTick);
            timer.Start();
        }

        private void OnTimerTick(object sender, EventArgs e)
        {
            DateTime curDate = DateTime.Now;
            string topLabelText = "현재시간 : ";
            topLabelText += curDate.Year.ToString() + "년";
            topLabelText += curDate.Month.ToString() + "월";
            topLabelText += curDate.Day.ToString() + "일";
            topLabelText += curDate.Hour.ToString() + "시";
            topLabelText += curDate.Minute.ToString() + "분";
            topLabelText += curDate.Second.ToString() + "초";

            topLabel.Text = topLabelText;
            //if (hasFinishedInitialization)
            //    drawChart(chartCtrl);
            // Trigger a view port changed event to update the chart
            chartCtrl.updateViewPort(true, false);
        }

        private void comboOpCode_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboOpCode.SelectedIndex >= 0)
            {
                if (comboOpCode.SelectedIndex == 0)
                    mMode = eSubjectMode.KOSPI;
                else if (comboOpCode.SelectedIndex == 1)
                    mMode = eSubjectMode.FUTURE;
                else
                    mMode = eSubjectMode.OPTION;

                // 차트 컨트롤을 갱신시켜서 새로운 차트를 볼 수 있게 한다.
                chartCtrl.updateViewPort(true, false);
            }
        }

        private void comboTarget_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboTarget.SelectedIndex >= 0)
            {
                if (comboTarget.SelectedIndex == 0)
                    mTarget = eTarget.ALL;
                else if (comboTarget.SelectedIndex == 1)
                    mTarget = eTarget.PERSON;
                else if (comboTarget.SelectedIndex == 2)
                    mTarget = eTarget.FOREIGN;
                else
                    mTarget = eTarget.ORGAN;

                // 차트 컨트롤을 갱신시켜서 새로운 차트를 볼 수 있게 한다.
                chartCtrl.updateViewPort(true, false);
            }
        }

        private bool mClosing = false;
        private void frmSubjectChart_FormClosing(object sender, FormClosingEventArgs e)
        {
            mClosing = true;
        }
    }
}
